package com.sumer.psychology.common.schedule;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.springframework.scheduling.support.TaskUtils;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * jdk标准的JOB
 * <p/>
 * User: zhenguang.zhu
 * Date: 2014/8/25
 * Time: 8:34
 */
public abstract class JDKTimerJob implements Runnable {
    private int initialDelay = 0;
    private int period = 0;
    private int shutdownTimeout = Integer.MAX_VALUE;
    private ScheduledExecutorService scheduledExecutorService;

    @PostConstruct
    public void start() {
        // 任何异常不会中断schedule执行, 由Spring TaskUtils的LOG_AND_SUPPRESS_ERROR_HANDLER進行处理
        Runnable task = TaskUtils.decorateTaskWithErrorHandler(this, null, true);

        // 创建单线程的SechdulerExecutor,并用guava的ThreadFactoryBuilder设定生成线程的名称
        scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setNameFormat(
                "NotificationTimerJob-%1$d").build());

        // scheduleAtFixedRatefixRate() 固定任务两次启动之间的时间间隔.
        // scheduleAtFixedDelay() 固定任务结束后到下一次启动间的时间间隔.
        scheduledExecutorService.scheduleAtFixedRate(task, initialDelay, period, TimeUnit.SECONDS);
    }

    @PreDestroy
    public void stop() {
        normalShutdown(scheduledExecutorService, shutdownTimeout, TimeUnit.SECONDS);
    }

    /**
     * 直接调用shutdownNow的方法, 有timeout控制.取消在workQueue中Pending的任务,并中断所有阻塞函数.
     */
    private void normalShutdown(ExecutorService pool, int timeout, TimeUnit timeUnit) {
        try {
            pool.shutdownNow();
            if (!pool.awaitTermination(timeout, timeUnit)) {
                System.err.println("Pool did not terminated");
            }
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 设置任务初始启动延时时间.
     */
    public void setInitialDelay(int initialDelay) {
        this.initialDelay = initialDelay;
    }

    /**
     * 设置任务间隔时间,单位秒.
     */
    public void setPeriod(int period) {
        this.period = period;
    }

    /**
     * 设置normalShutdown的等待时间, 单位秒.
     */
    public void setShutdownTimeout(int shutdownTimeout) {
        this.shutdownTimeout = shutdownTimeout;
    }
}
